package com.hd.common.utils;

import com.alibaba.fastjson.JSONObject;
import com.hd.common.rest.factory.HttpsClientRequestFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * @author chentl
 * @version V1.0
 * @Project 交通运输第三方监测平台
 * @Title RestUtils.java
 * @Description 远程调用工具类
 * @Package com.hd.common.utils
 * @date 2021/1/13 5:46 下午
 * @Copyright: 深圳市宏电技术股份有限公司 All rights reserved.
 */
@Component
@Slf4j
public class RestUtils {


    // 默认时间五秒，不重试。
    private final static int CONNEC_TIMEOUT = 5000;
    private final static int READ_TIMEOUT = 5000;
    private final static int RETRY_COUNT = 1;


    /**
     * @return java.lang.String
     * @author chentl
     * @description https 请求 GET | 支持 连接超时、读取超时、重试次数
     * @date 2021/1/13 5:46 下午
     * @params [url, connecTimeout, readTimeout, retryCount]
     */
    public static String getHttp(String url, int connecTimeout, int readTimeout, int retryCount) {
        RestTemplate restTemplate = simpeClient(url, connecTimeout, readTimeout);
        String result = null; // 返回值类型;
        for (int i = 1; i <= retryCount; i++) {
            try {
                result = restTemplate.getForObject(url, String.class);
                return result;
            } catch (RestClientException e) {
                log.error("-----------开始-----------重试count: " + i);
                e.printStackTrace();
            }
        }
        return null;
    }


    /**
     * @return java.lang.String
     * @author chentl
     * @description https 请求 GET
     * @date 2021/1/13 5:46 下午
     * @params [url]
     */
    public static String getHttp(String url) {
        RestTemplate restTemplate = simpeClient(url, CONNEC_TIMEOUT, READ_TIMEOUT);
        return restTemplate.getForObject(url, String.class);
    }

    /**
     * @return java.lang.String
     * @author chentl
     * @description http 请求 POST | 支持 连接超时、读取超时、重试次数
     * @date 2021/1/13 5:47 下午
     * @params [url, params, headersMap, connecTimeout, readTimeout, retryCount]
     */
    public static String postHttp(String url, JSONObject params, Map headersMap, int connecTimeout, int readTimeout, int retryCount) {
        RestTemplate restTemplate = simpeClient(url, connecTimeout, readTimeout);
        // 设置·header信息
        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.setAll(headersMap);
        HttpEntity<JSONObject> requestEntity = new HttpEntity<>(params, requestHeaders); // josn utf-8 格式
        String result = null; // 返回值类型;
        try {
            result = restTemplate.postForObject(url, requestEntity, String.class);
            return result;
        } catch (RestClientException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * @return java.lang.String
     * @author chentl
     * @description http 请求 post
     * @date 2021/1/13 5:47 下午
     * @params [url, params, headersMap]
     */
    public static String postHttp(String url, JSONObject params, Map headersMap) {
        RestTemplate restTemplate = simpeClient(url, CONNEC_TIMEOUT, READ_TIMEOUT);
        // 设置·header信息
        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.setAll(headersMap);
        HttpEntity<JSONObject> requestEntity = new HttpEntity<JSONObject>(params, requestHeaders);
        try {
            String result = restTemplate.postForObject(url, requestEntity, String.class);
            return result;
        } catch (RestClientException e) {
            log.error("RestUtils 调用目标API失败");
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 加密参数类型请求  application/x-www-form-urlencoded
     * MultiValueMap<String, Object>
     * 采用 HttpEntity<MultiValueMap<String, Object>> 构造
     * http 请求 post
     *
     * @param url            地址
     * @param postParameters 参数
     * @param headersMap     header
     * @param connecTimeout  连接时间
     * @param readTimeout    读取时间
     * @param retryCount     重试机制
     * @return String 类型
     */
    public static String postHttpEncryption(String url, MultiValueMap<String, Object> postParameters, Map headersMap, int connecTimeout, int readTimeout, int retryCount) {
        RestTemplate restTemplate = simpeClient(url, connecTimeout, readTimeout);
        // 设置·header信息
        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.setAll(headersMap);
        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(postParameters, requestHeaders);
        String result = null; // 返回值类型;
        for (int i = 1; i <= retryCount; i++) {
            try {
                result = restTemplate.postForObject(url, requestEntity, String.class);
                return result;
            } catch (RestClientException e) {
                log.error("-----------开始-----------重试count: " + i);
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 加密参数类型请求  application/x-www-form-urlencoded
     * MultiValueMap<String, Object>
     * 采用 HttpEntity<MultiValueMap<String, Object>> 构造
     * http 请求 post
     *
     * @param url            地址
     * @param postParameters 参数
     * @param headersMap     header
     * @return String 类型
     */
    public static String postHttpEncryption(String url, MultiValueMap<String, Object> postParameters, Map headersMap) {
        RestTemplate restTemplate = simpeClient(url, CONNEC_TIMEOUT, READ_TIMEOUT);
        // 设置·header信息
        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.setAll(headersMap);
        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(postParameters, requestHeaders);
        String result = restTemplate.postForObject(url, requestEntity, String.class);
        return result;
    }


    private static RestTemplate simpeClient(String url, int connecTimeout, int readTimeout) {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setConnectTimeout(connecTimeout);
        requestFactory.setReadTimeout(readTimeout);
        RestTemplate restTemplate = new RestTemplate(requestFactory);
        // 设置编码集
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        //error处理
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler());
        if (url.contains("https")) {
            // 绕过https
            restTemplate.setRequestFactory(new HttpsClientRequestFactory());
        }
        return restTemplate;
    }


    /**
     * @ClassName: DefaultResponseErrorHandler
     * @Description:
     * @author:
     * @date: 2
     */
    private static class DefaultResponseErrorHandler implements ResponseErrorHandler {

        /**
         * 对response进行判断，如果是异常情况，返回true
         */
        @Override
        public boolean hasError(ClientHttpResponse response) throws IOException {
            return response.getStatusCode().value() != HttpServletResponse.SC_OK;
        }

        /**
         * 异常情况时的处理方法
         */
        @Override
        public void handleError(ClientHttpResponse response) throws IOException {
            BufferedReader br = new BufferedReader(new InputStreamReader(response.getBody()));
            StringBuilder sb = new StringBuilder();
            String str = null;
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            try {
                throw new Exception(sb.toString());
            } catch (Exception e) {
                log.error("Api调用后目标服务器发生异常，返回结果为：{}", JSONObject.toJSONString(e.getMessage()));
            }
        }
    }
}


